package sh.spring;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import sh.base.aop.ProxyManager;
import sh.base.aop.TargetSource;
import sh.base.aop.util.ReflectUtil;
import sh.orm.Session;
import sh.orm.SessionFactory;
import sh.spring.annotation.Autowired;
import sh.spring.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lqq
 * @date 2019/2/22
 */
public class BeanFactoryImpl implements BeanFactory {

    private Map<Class<?>, Object> beansMap = new ConcurrentHashMap<>();


    @Override
    public <T> T getBean(Class<T> clazz) {

        // 如果工厂中有bean，则从工厂中直接返回。
        Object bean;
        if(beansMap.get(clazz) != null){
            return (T)beansMap.get(clazz);
        }
        if(needProxy(clazz)){
            bean = getProxyObject(clazz);
        }else{
            try {
                bean = clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
                throw new SpringException("生成对象实例异常" + e.getMessage());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                throw new SpringException("生成对象实例异常" + e.getMessage());
            }
        }

        inject(bean);
        //放入bean map中
        beansMap.put(clazz, bean);

        return (T) bean;
    }

    /**
     * 是否需要代理,当前只判断@Transactional注解，还可以扩展
     * @param clazz
     * @return
     */
    private boolean needProxy(Class<?> clazz){
        // 如果有@Transactional 注解，则需要代理
       return ReflectUtil.methodHasAnnotation(clazz , Transactional.class);
    }

    /**
     * 暂时只注入@Autowired 的东西
     * @param bean 要注入的bean
     */
    private void inject(Object bean) {
        List<Field> fieldList = ReflectUtil.getAutowiredFields(bean.getClass(), Autowired.class);
        for(Field field : fieldList){
            ReflectUtil.setFieldValue(field, bean, getBean(field.getType()));
        }
    }



    /**
     * 获取已经增强的对象
     * // 有不同的注解需要进行不用的拦截， TODO
     *
     * @param clazz
     * @return
     */
    private Object getProxyObject(Class<?> clazz) {
        Object instance = null;
        try {
            instance = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new SpringException("生成实例对象异常" + e.getMessage());
        }

        // 通过统一拦截接口实现方法拦截

        //统一获取代理对象的地方
        ProxyManager proxyManager = new ProxyManager();
        proxyManager.setMethodInterceptor(new TransactionInterceptor());
        proxyManager.setTargetSource(new TargetSource(instance , clazz, null));
        return proxyManager.getProxy();
    }

    /**
     * 拦截管理器添加上对象的拦截方法
     */
    class TransactionInterceptor implements MethodInterceptor{

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            //判断方法上是否有事务注解
            if(!invocation.getMethod().isAnnotationPresent(Transactional.class)){
                return invocation.proceed();
            }

            // 拿到session开启事务
            Session session = SessionFactory.getInstance().getSession();
            session.beginTransaction();
            // 根据执行的结果判断是回滚还是提交
            Object ret = null;
            try{
                // 执行service操作
                ret = invocation.proceed();
            }catch (Exception e){
                //    有异常，回滚事务
                session.rollback();
                throw  new TransactionException("事务异常" + e.getMessage());
            }

            // 没有异常，提交事务
            session.commit();
            return ret;
        }
    }


}
